/*
 * Copyright (c) 2022, Chongqing UCchip InfoTech Co.,Ltd
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * @brief MQTT communication
 *
 * Change Logs:
 * Date           Author       Notes
 * 2023-01-30     jlu          the first version
 */
#include <rtthread.h>
#include "resource_manager.h"

#define DBG_TAG "resource"
#include "uc_log.h"

#ifdef RT_TASK_RESOURCE_TOOL

static char *g_status[] =
    {
        "init",    /* RT_THREAD_INIT */
        "ready",   /* RT_THREAD_READY */
        "suspend", /* RT_THREAD_SUSPEND */
        "running", /* RT_THREAD_RUNNING */
        "close",   /* RT_THREAD_CLOSE */
};

static void hook_test_resource_task(struct rt_thread *from, struct rt_thread *to)
{
    from->task_run_all_time += rt_tick_get() - from->task_current_start_time;
    to->task_current_start_time = rt_tick_get();
}

void resource_manager_init(void)
{
    rt_scheduler_sethook(hook_test_resource_task);
}

/**
 * @brief resource manager
 *
 * @param mode the print mode
 */
void resource_manager(int mode)
{
    if (mode == RESOURCE_DETAIL_MODE)
    {
        print_thread_resource();
        print_memory_resource();
        TRACE_W("--------------------------------------------------------");
    }
    else
    {
        print_memory_resource();
    }
}

/**
 * @brief print memory resource
 *
 */
void print_memory_resource(void)
{
    unsigned int total = 0;
    unsigned int used = 0;
    unsigned int max_used = 0;
    static unsigned int run_time = 0;
    static unsigned int last_tick = 0;

    if (rt_tick_get() >= last_tick)
    {
        run_time += ((rt_tick_get() - last_tick) / 1000);
    }
    else
    {
        run_time += ((UINT32_MAX - last_tick + rt_tick_get()) / 1000);
    }
    last_tick = rt_tick_get();

    rt_memory_info(&total, &used, &max_used);
    TRACE_W("total %d used %d rate %d%% max %d, run time %us", total, used, used * 100 / total, max_used, run_time);
}

void print_thread_resource(void)
{
    struct rt_thread *thread = RT_NULL;
    struct rt_list_node *node = RT_NULL;
    struct rt_object_information *info = RT_NULL;

    TRACE_W("--------------------------------------------------------");
    TRACE_W("%-*.s priority  cpu  stack   used  rate   status", RT_NAME_MAX, "thread");
    TRACE_W("--------------------------------------------------------");
    /* for each thread */
    info = rt_object_get_information((enum rt_object_class_type)RT_Object_Class_Thread);
    for (node = info->object_list.next; node != &(info->object_list); node = node->next)
    {
        rt_thread_mdelay(1);
        thread = rt_list_entry(node, struct rt_thread, list);
        /* free stack size */
        rt_uint8_t *ptr = (rt_uint8_t *)thread->stack_addr;
        while (*ptr == '#')
            ptr++;
        rt_ubase_t free_size = (rt_ubase_t)ptr - (rt_ubase_t)thread->stack_addr;
        rt_ubase_t used_rate = (thread->stack_size - free_size) * 100 / thread->stack_size;
        /* print thread information */
        TRACE_W("%-*.s %5d   %5d %6d %6d %4d%% %8s",
                RT_NAME_MAX, thread->name,
                thread->current_priority,
                thread->task_run_all_time,
                thread->stack_size,
                thread->stack_size - free_size,
                used_rate,
                g_status[thread->stat & RT_THREAD_STAT_MASK]);
        /* reset counter */
        thread->task_run_all_time = 0;
    }
    TRACE_W("--------------------------------------------------------");
}

#endif
